﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using DSS_XNA.Engine.World.Worlds.RPGWorld;

namespace TileMapEditor
{
    public partial class ctrlTileSet : UserControl
    {
        #region Properties

        public int OffsetX
        {
            get { return _offsetX; }
            set { _offsetX = value; }
        }
        private int _offsetX = 0;

        public int OffsetY
        {
            get { return _offsetY; }
            set { _offsetY = value; }
        }
        private int _offsetY = 0;

        public Bitmap TileMap
        {
            get { return _tileMap; }
            set { _tileMap = value; }
        }
        private Bitmap _tileMap = null;

        public int TileWidth
        {
            get { return _tileWidth; }
            set { _tileWidth = value; }
        }
        private int _tileWidth = 32;

        public int TileHeight
        {
            get { return _tileHeight; }
            set { _tileHeight = value; }
        }
        private int _tileHeight = 32;

        public int MouseOverTileIdx
        {
            get { return _mouseOverTileIdx; }
            set { _mouseOverTileIdx = value; }
        }
        private int _mouseOverTileIdx = -1;

        public int SelectedTileIdx
        {
            get { return _selectedTileIdx; }
            set { _selectedTileIdx = value; }
        }
        private int _selectedTileIdx = -1;

        public Rectangle SelectedTileSourceRect
        {
            get { return _selectedTileSourceRect; }
            set { _selectedTileSourceRect = value; }
        }
        private Rectangle _selectedTileSourceRect = new Rectangle();

        public TileSetManager MyTileSetManager
        {
            get { return _tileSetManager; }
        }
        private TileSetManager _tileSetManager = new TileSetManager();

        public int CurrentTileSetIdx
        {
            get { return _currentTileSetIdx; }
            set { _currentTileSetIdx = value; }
        }
        private int _currentTileSetIdx = 0;

        #endregion

        #region Methods

        public ctrlTileSet()
        {
            InitializeComponent();
        }

        private void buttonLoadTileSet_Click(object sender, EventArgs e)
        {
            DialogResult res = this.openTileMap.ShowDialog();
            if (res == DialogResult.Cancel)
                return;

            if (this.TileMap != null)
            {
                this.TileMap.Dispose();
                this.TileMap = null;

                this.OffsetX = 0;
                this.OffsetY = 0;

                this.scrollhTileMap.Value = this.scrollhTileMap.Minimum;
                this.scrollvTileMap.Value = this.scrollvTileMap.Minimum;

                this.ResetSelectedTile();
            }

            Stream stream = this.openTileMap.OpenFile();
            this.TileMap = (Bitmap)Bitmap.FromStream(stream);

            stream.Close();

            this.pictureTileMap.SizeMode = PictureBoxSizeMode.Normal;

            this.RefreshTileSet();

            string fname = Path.GetFileName(this.openTileMap.FileName);
            TileSet ts = new TileSet();
            ts.Create(fname);
            this.MyTileSetManager.TileSets.Add(ts);
            this.CurrentTileSetIdx = this.MyTileSetManager.TileSets.Count - 1;
        }

        #endregion

        private void scrollvTileMap_Scroll(object sender, ScrollEventArgs e)
        {
            this.OffsetY += e.NewValue - e.OldValue;
            this.UpdateTileMapPictureBox();
        }

        private void scrollhTileMap_Scroll(object sender, ScrollEventArgs e)
        {
            this.OffsetX += e.NewValue - e.OldValue;
            this.UpdateTileMapPictureBox();
        }

        private void UpdateTileMapPictureBox()
        {
            if (this.TileMap == null)
                return;

            Rectangle sourceRect = new Rectangle();
            sourceRect.X = this.OffsetX;
            sourceRect.Y = this.OffsetY;
            sourceRect.Width = (this.TileMap.Width > this.pictureTileMap.Width) ?
                this.pictureTileMap.Width : this.TileMap.Width;
            sourceRect.Height = (this.TileMap.Height > this.pictureTileMap.Height) ?
                this.pictureTileMap.Height : this.TileMap.Height;

            Bitmap bmp = this.TileMap.Clone(sourceRect, System.Drawing.Imaging.PixelFormat.Format16bppRgb565);

            // draw the tile lines?
            if (this.TileWidth > 0 && this.TileHeight > 0)
            {
                System.Drawing.Graphics g = Graphics.FromImage(bmp);

                int numX = this.TileMap.Width / this.TileWidth;
                int numY = this.TileMap.Height / this.TileHeight;

                numX++; // account for any floating point cutoffs
                numY++;

                Pen pen = new Pen(new SolidBrush(Color.Yellow));

                for (int i = 0; i < numX; i++)
                {
                    int x = i * this.TileWidth;
                    x -= this.OffsetX;
                    Point p1 = new Point(x, 0);
                    Point p2 = new Point(x, bmp.Height - 1);

                    g.DrawLine(pen, p1, p2);
                }

                for (int i = 0; i < numY; i++)
                {
                    int y = i * this.TileHeight;
                    y -= this.OffsetY;
                    Point p1 = new Point(0, y);
                    Point p2 = new Point(this.TileMap.Width - 1, y);

                    g.DrawLine(pen, p1, p2);
                }

                if (this.MouseOverTileIdx > -1)
                {
                    int tileWidth = this.TileMap.Width / this.TileWidth;

                    int x = this.MouseOverTileIdx % tileWidth;
                    int y = this.MouseOverTileIdx / tileWidth;

                    x *= this.TileWidth;
                    y *= this.TileHeight;

                    if(this.OffsetX > 0)
                        x -= this.OffsetX % this.TileWidth;
                    if(this.OffsetY > 0)
                        y -= this.OffsetY % this.TileHeight;

                    Point p1 = new Point(x, y);
                    Point p2 = new Point(x + this.TileWidth, y);
                    Point p3 = new Point(x + this.TileWidth, y + this.TileHeight);
                    Point p4 = new Point(x, y + this.TileHeight);

                    Pen redPen = new Pen(new SolidBrush(Color.Red));

                    g.DrawLine(redPen, p1, p2);
                    g.DrawLine(redPen, p2, p3);
                    g.DrawLine(redPen, p3, p4);
                    g.DrawLine(redPen, p4, p1);
                }

                if (this.SelectedTileIdx > -1)
                {
                    int tileWidth = this.TileMap.Width / this.TileWidth;

                    int x = this.SelectedTileIdx % tileWidth;
                    int y = this.SelectedTileIdx / tileWidth;

                    x *= this.TileWidth;
                    y *= this.TileHeight;

                    x -= this.OffsetX;
                    y -= this.OffsetY;

                    Point p1 = new Point(x, y);
                    Point p2 = new Point(x + this.TileWidth, y);
                    Point p3 = new Point(x + this.TileWidth, y + this.TileHeight);
                    Point p4 = new Point(x, y + this.TileHeight);

                    Pen redPen = new Pen(new SolidBrush(Color.Green));

                    g.DrawLine(redPen, p1, p2);
                    g.DrawLine(redPen, p2, p3);
                    g.DrawLine(redPen, p3, p4);
                    g.DrawLine(redPen, p4, p1);
                }

                g.Save();
            }

            this.pictureTileMap.Image = bmp;
        }

        private void pictureTileMap_Resize(object sender, EventArgs e)
        {
            this.RefreshTileSet();
        }

        private void RefreshTileSet()
        {
            if (this.TileMap.Width > this.pictureTileMap.Width)
            {
                this.scrollhTileMap.Minimum = this.pictureTileMap.Width;
                this.scrollhTileMap.Maximum = this.TileMap.Width;
                this.scrollhTileMap.Enabled = true;
            }
            else
            {
                this.scrollhTileMap.Enabled = false;
            }

            if (this.TileMap.Height > this.pictureTileMap.Height)
            {
                this.scrollvTileMap.Minimum = this.pictureTileMap.Height;
                this.scrollvTileMap.Maximum = this.TileMap.Height;
                this.scrollvTileMap.Enabled = true;
            }
            else
            {
                this.scrollvTileMap.Enabled = false;
            }

            this.UpdateTileMapPictureBox();
        }

        private void pictureTileMap_SizeChanged(object sender, EventArgs e)
        {
            this.RefreshTileSet();
        }

        private void textTileWidth_Leave(object sender, EventArgs e)
        {
            int size = 0;
            if (int.TryParse(this.textTileWidth.Text, out size))
            {
                this.TileWidth = size;
                this.UpdateTileMapPictureBox();
            }
        }

        private void textTileHeight_Leave(object sender, EventArgs e)
        {
            int size = 0;
            if (int.TryParse(this.textTileHeight.Text, out size))
            {
                this.TileHeight = size;
                this.UpdateTileMapPictureBox();
            }
        }

        private void pictureTileMap_MouseMove(object sender, MouseEventArgs e)
        {
            this.MouseOverTileIdx = this.GetTileIdx(e.X, e.Y);
            if(MouseOverTileIdx > -1)
                this.UpdateTileMapPictureBox();
        }

        private int GetTileIdx(int x, int y)
        {
            if (this.TileMap == null ||
                this.TileWidth == 0 ||
                this.TileHeight == 0)
                return -1;

            x = x == 0 ? 1 : x;
            y = y == 0 ? 1 : y;

            x += this.OffsetX % this.TileWidth;
            y += this.OffsetY % this.TileHeight;

            float fx = x / this.TileWidth;

            float fy = y / this.TileHeight;

            int tileWidth = this.TileMap.Width / this.TileWidth;

            int idx = Convert.ToInt32(fx + (fy * tileWidth));

            return idx;
        }

        private void pictureTileMap_MouseLeave(object sender, EventArgs e)
        {
            this.MouseOverTileIdx = -1;
        }

        private void pictureTileMap_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.MouseOverTileIdx == -1)
                    return;

                this.SelectedTileIdx = this.MouseOverTileIdx;

                this.RefreshSelectedTile();
            }
            else
            {
                this.ResetSelectedTile();
            }
        }

        private void ResetSelectedTile()
        {
            this.SelectedTileIdx = -1;
            this.SelectedTileSourceRect = new Rectangle();
            if (this.panelSelectedTile.BackgroundImage != null)
            {
                this.panelSelectedTile.BackgroundImage.Dispose();
                this.panelSelectedTile.BackgroundImage = null;
            }
        }

        private void RefreshSelectedTile()
        {
            int tileWidth = this.TileMap.Width / this.TileWidth;

            int x = this.MouseOverTileIdx % tileWidth;
            int y = this.MouseOverTileIdx / tileWidth;

            x *= this.TileWidth;
            y *= this.TileHeight;

            x += this.OffsetX;
            y += this.OffsetY;

            if (this.OffsetX > 0)
                x -= this.OffsetX % this.TileWidth;
            if (this.OffsetY > 0)
                y -= this.OffsetY % this.TileHeight;

            Point p1 = new Point(x, y);
            Size size = new Size(this.TileWidth, this.TileHeight);

            this.SelectedTileSourceRect = new Rectangle(p1, size);

            Bitmap bmp = this.TileMap.Clone(this.SelectedTileSourceRect,
                System.Drawing.Imaging.PixelFormat.Format16bppRgb565);

            if (this.panelSelectedTile.BackgroundImage != null)
            {
                this.panelSelectedTile.BackgroundImage.Dispose();
                this.panelSelectedTile.BackgroundImage = null;
            }
            this.panelSelectedTile.BackgroundImage = bmp;
        }

        private void ctrlTileSet_Load(object sender, EventArgs e)
        {
            this.TileWidth = 32;
            this.TileHeight = 32;

            this.textTileWidth.Text = this.TileWidth.ToString();
            this.textTileHeight.Text = this.TileHeight.ToString();
        }
    }
}
